package logic.topology;

import eduni.simjava.Sim_entity;
import java.util.Collection;
import java.util.LinkedList;
import java.util.Vector;
import logic.topology.NetworkLink;
import logic.topology.NetworkNode;

/**
 * Uzol v grafe.
 */
public abstract class NetworkNode {
    /**
     * x-ova suradnica stredu
     */
    private int centerX;

    /**
     * y-ova suradnica stredu
     */
    private int centerY;

    /**
     * zoznam inicidentnych liniek
     */
    private Vector<NetworkLink> links;

    /**
     * jedinecne meno v ramci celej topologie
     */
    private String name;

    /**
     * Vytvorenie uzla a jeho zaregistrovanie do GridTopology. Ak uz uzol s danym 
     *    menom existuje, vyhodi Exception
     */
    public NetworkNode(String nodeName, int x, int y) throws Exception {
        setName(nodeName);
        links = new Vector<NetworkLink>();
        setCenterX(x);
        setCenterY(y);
        GridTopology.addNode(this);
    }

    public int getCenterX() {
        return centerX;
    }

    public void setCenterX(int val) {
        this.centerX = val;
    }

    public int getCenterY() {
        return centerY;
    }

    public void setCenterY(int val) {
        this.centerY = val;
    }

    public void setCenterXY(int x, int y) {
        this.centerX = x;
        this.centerY = y;
    }

    /**
     * Pridanie linky do zoznamu - bez kontroly. Malo by sa volat pri vytvoreni 
     *    linky.
     */
    void insertLink(NetworkLink newLink) {
        links.add(newLink);
    }

    public Collection<NetworkLink> getLinks() {
        return links;
    }

    /**
     * @param   node    zadany uzol
     * @return  true, ak je uzol incidentny so zadanym uzlom
     */
    public boolean hasLinkTo(NetworkNode node) {
       for(NetworkLink l : links) 
           if (l.getAnotherEnd(this) == node)
               return true;
       
       return false;
    }
    
    /**
     * @return null, ak je mozne vytvorit novu linku z daneho uzla
     * (este sa nevie, aky bude koniec linky). Inak vracia dovod, preco sa nemoze 
     * vytvorit
     */
    public abstract String canCreateNewLink();

    /**
     * @return null, ak moze vytvorit spojenie s danym elementom. Inak vracia
     * dovod, preco nie. Kontroluje aj, ci uz linka s danym elementom neexistuje.
     */
    public abstract String canCreateNewLink(NetworkNode end);

    /**
     * @return entity, ktore predstavuju ekvivalent tohto uzla v baliku gridSim
     */
    public abstract LinkedList<Sim_entity> createGridSimEntities(
            String globalBrokerName,
            boolean trace_flag
            ) throws Exception;
    
    
    /**
     * Odstranenie linky zo zoznamu.
     */
    void removeLink(NetworkLink link) {
        links.removeElement(link);
    }

    public String getName() {
        return name;
    }

    /**
     * Nastavenie mena uzla. Kontroluje sa jeho jedinecnost.
     */
    public void setName(String val) throws Exception {
        if (val.equals(this.name))
            return;     //netreba znovu nastavovat
        
        if (val.isEmpty())
           throw new Exception("Name must be defined!");        
        
        if (GridTopology.existsNode(val)) 
            throw new Exception("Node with name " + val + " already exists!");
        
        this.name = val;
    }

    /**
     * Odstranenie uzlu z topologie, spolu s jeho incidentnymi hranami.
     */
    public void remove() {
        //vytvori sa kopia zoznamu incidentnych hran, aby pri rekurzivnom volani
        //odstranenia hrany nedoslo ku konkurencii iteratorov
        Vector<NetworkLink> oldLinks = new Vector<NetworkLink>(links);
        links.clear();
        
        for(NetworkLink link: oldLinks)
            link.remove();
        
        oldLinks.clear();
        GridTopology.removeNode(this);
        links = null;
        oldLinks = null;
    }
}
